﻿// Copyright (c) Microsoft Corp.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//     http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using NUnit.Framework;

using Microsoft.Health.Mobile;
using System.Threading;
using System.Xml.Linq;

namespace TestRegular
{
    [TestFixture]
    public class HealthVaultServiceTest
    {
        static AutoResetEvent asyncTestEvent;
        static HealthVaultResponseEventArgs eventArgs;

        void CheckXmlForString(HealthVaultRequest request, string searchValue)
        {
            WebRequestMock mockRequest = (WebRequestMock) request.WebRequest;

            if (!mockRequest.RequestXml.Contains(searchValue))
            {
                Assert.Fail("Content missing from request - " + searchValue);
            }
        }

        HealthVaultService GetNullService()
        {
            return new HealthVaultService("http://www.sample.com/platform", "http://www.sample.com/shell", Guid.Empty);
        }

        [Test]
        public void ResponseObjectCorrect()
        {
            HealthVaultService service = GetNullService();

            XElement info = new XElement("info", "My request data");
            HealthVaultRequest request = new HealthVaultRequest("GetThings", "2", info, SendRequestResponseReceived);
            request.WebRequest = new WebRequestMock("<response><status><code>55</code></status></response>");

            asyncTestEvent = new AutoResetEvent(false);
            service.BeginSendRequest(request);

            asyncTestEvent.WaitOne();

            Assert.IsNotNull(eventArgs.Response);
            Assert.AreEqual(55, eventArgs.Response.StatusCode);
        }

        [Test]
        public void TestInfoHash()
        {
            HealthVaultService service = GetNullService();

            XElement info = new XElement("info", new XElement("data"));
            HealthVaultRequest request = new HealthVaultRequest("GetThings", "2", info, SendRequestResponseReceived);
            request.WebRequest = new WebRequestMock(GetServiceDefinitionXml);

            asyncTestEvent = new AutoResetEvent(false);
            service.BeginSendRequest(request);

            asyncTestEvent.WaitOne();

            Assert.AreEqual(request, eventArgs.Request);
            Console.WriteLine(((WebRequestMock)request.WebRequest).RequestXml);
            CheckXmlForString(request, @"<hash-data algName=""SHA256"">so4ytpjC0gRMGmO3v9eo/oiORDAWnrDsRvTAFOvswic=</hash-data>");
        }

        [Test]
        public void TestVersionPassed()
        {
            HealthVaultService service = GetNullService();

            XElement info = new XElement("info", "My request data");
            HealthVaultRequest request = new HealthVaultRequest("GetThings", "2", info, SendRequestResponseReceived);
            request.WebRequest = new WebRequestMock(GetServiceDefinitionXml);

            asyncTestEvent = new AutoResetEvent(false);
            service.BeginSendRequest(request);

            asyncTestEvent.WaitOne();

            Assert.AreEqual(request, eventArgs.Request);
            Console.WriteLine(((WebRequestMock)request.WebRequest).RequestXml);
            CheckXmlForString(request, @"<version>" + MobilePlatform.PlatformAbbreviationAndVersion + "</version>");
        }

        [Test]
        public void TestAuthTokenPresent()
        {
            HealthVaultService service = GetNullService();
            service.AuthorizationSessionToken = "ASAAADNt1Jwbx…+wsXjPFs00soe9w==";

            XElement info = new XElement("info", "My request data");
            HealthVaultRequest request = new HealthVaultRequest("GetThings", "2", info, SendRequestResponseReceived);
            request.WebRequest = new WebRequestMock(GetServiceDefinitionXml);

            asyncTestEvent = new AutoResetEvent(false);
            service.BeginSendRequest(request);

            asyncTestEvent.WaitOne();

            Assert.AreEqual(request, eventArgs.Request);
            Console.WriteLine(((WebRequestMock)request.WebRequest).RequestXml);
            CheckXmlForString(request, @"<auth-token>ASAAADNt1Jwbx…+wsXjPFs00soe9w==</auth-token>");
        }

        [Test]
        public void TestAppIdPresent()
        {
            HealthVaultService service = GetNullService();
            service.AppIdInstance = new Guid("ce121dd2-7b5b-40f4-b41f-01d16f23e391");

            XElement info = new XElement("info", "My request data");
            HealthVaultRequest request = new HealthVaultRequest("GetThings", "2", info, SendRequestResponseReceived);
            request.WebRequest = new WebRequestMock(GetServiceDefinitionXml);

            asyncTestEvent = new AutoResetEvent(false);
            service.BeginSendRequest(request);

            asyncTestEvent.WaitOne();

            Assert.AreEqual(request, eventArgs.Request);
            Console.WriteLine(((WebRequestMock)request.WebRequest).RequestXml);
            CheckXmlForString(request, @"<app-id>ce121dd2-7b5b-40f4-b41f-01d16f23e391</app-id>");
        }

        [Test]
        public void TestHmacPresent()
        {
            HealthVaultService service = GetNullService();
            service.AuthorizationSessionToken = "ASAAADNt1Jwbx…+wsXjPFs00soe9w==";
            service.SessionSharedSecret = Convert.ToBase64String(Encoding.UTF8.GetBytes("My test key"));

            XElement info = new XElement("info", "My request data");
            HealthVaultRequest request = new HealthVaultRequest("GetThings", "2", info, SendRequestResponseReceived);
            request.MessageTime = new DateTime(2011, 1, 1, 1, 1, 1);
            request.WebRequest = new WebRequestMock(GetServiceDefinitionXml);

            asyncTestEvent = new AutoResetEvent(false);
            service.BeginSendRequest(request);

            asyncTestEvent.WaitOne();

            Assert.AreEqual(request, eventArgs.Request);
            Console.WriteLine(((WebRequestMock)request.WebRequest).RequestXml);
            CheckXmlForString(request, @"<auth><hmac-data algName=""HMACSHA256"">xk0gZs+cg3FOytzjoDwgxalTPHyW+eTvGN6S7g2Rn4Y=</hmac-data></auth>");
        }

        [Test]
        public void ResponseSimpleError()
        {
            HealthVaultService service = GetNullService();

            XElement info = new XElement("info", "My request data");
            HealthVaultRequest request = new HealthVaultRequest("GetThings", "2", info, SendRequestResponseReceived);
            request.WebRequest = new WebRequestMock("<response><status><code>5</code><error><message>Unknown method GetServiceDefinitionss</message></error></status></response>");

            asyncTestEvent = new AutoResetEvent(false);
            service.BeginSendRequest(request);

            asyncTestEvent.WaitOne();

            Assert.IsNotNull(eventArgs.Response);
            Assert.AreEqual(5, eventArgs.Response.StatusCode);
            Assert.IsTrue(eventArgs.ErrorText.Contains("Unknown method GetServiceDefinitionss"));
        }


        [Test]
        public void LanguageAndCountry()
        {
            HealthVaultService service = GetNullService();
            service.Country = "CA";
            service.Language = "fr";

            XElement info = new XElement("info", "My request data");
            HealthVaultRequest request = new HealthVaultRequest("GetThings", "2", info, SendRequestResponseReceived);
            request.WebRequest = new WebRequestMock("<response><status><code>5</code><error><message>Unknown method GetServiceDefinitionss</message></error></status></response>");

            asyncTestEvent = new AutoResetEvent(false);
            service.BeginSendRequest(request);

            asyncTestEvent.WaitOne();

            Assert.IsNotNull(eventArgs.Response);
            CheckXmlForString(request, @"<country>CA</country>");
            CheckXmlForString(request, @"<language>fr</language>");
        }

        [Test]
        public void GetApplicationCreationUrlNoApplicationYet()
        {
            Guid masterAppId = Guid.NewGuid();
            HealthVaultService service = new HealthVaultService(null, "https://account.healthvault-ppe.com/", masterAppId);
            string appToken = "ASAAADNt1Jwbx…+wsXjPFs00soe9w==";
            service.ApplicationCreationToken = appToken;

            string url = service.GetApplicationCreationUrl();

            Uri uri = new Uri(url);
            Assert.IsTrue(url.Contains("target=CREATEAPPLICATION"));
            int targetSpot = url.IndexOf("targetqs=");

            string targetqs = url.Substring(targetSpot + "targetqs=".Length);
            targetqs = Uri.UnescapeDataString(targetqs);

            Assert.IsTrue(targetqs.Contains("appCreationToken=" + Uri.EscapeDataString(appToken)));
            Assert.IsTrue(targetqs.Contains("instanceName=" + Uri.EscapeDataString("Windows Phone")));
        }

        [Test]
        public void SaveRestoreState()
        {
            HealthVaultService service = new HealthVaultService("https://platform.healthvault-ppe.com", "https://account.healthvault-ppe.com/", Guid.NewGuid());

            service.AppIdInstance = new Guid("ce121dd2-7b5b-40f4-b41f-01d16f23e391");
            service.ApplicationCreationToken = "ASAAADNt1Jwbx…+wsXjPFs00soe9w==xxx";
            service.AuthorizationSessionToken = "ASAAADNt1Jwbx…+wsXjPFs00soe9w==";
            service.SharedSecret = Convert.ToBase64String(Encoding.UTF8.GetBytes("My test key"));
            service.Country = "CA";
            service.Language = "fr";
            service.SessionSharedSecret = Convert.ToBase64String(Encoding.UTF8.GetBytes("My session key"));

            Guid personId = Guid.NewGuid();
            string personName = "Fred";
            Guid recordId = Guid.NewGuid();

            service.CurrentRecord = CreateRecord(personId, personName, recordId);
            service.SaveSettings("TestSettings");

            HealthVaultService service2 = new HealthVaultService("https://platform.healthvault-ppe.com", "https://account.healthvault-ppe.com/", Guid.NewGuid());
            service2.LoadSettings("TestSettings");

            Assert.AreEqual(service.AppIdInstance, service2.AppIdInstance);
            Assert.AreEqual(null, service2.ApplicationCreationToken);
            Assert.AreEqual(service.AuthorizationSessionToken, service2.AuthorizationSessionToken);
            Assert.AreEqual(service.SharedSecret, service2.SharedSecret);
            Assert.AreEqual(service.Country, service2.Country);
            Assert.AreEqual(service.Language, service2.Language);
            Assert.AreEqual(service.SessionSharedSecret, service2.SessionSharedSecret);

            Assert.AreEqual(service.CurrentRecord.PersonId, service2.CurrentRecord.PersonId);
            Assert.AreEqual(service.CurrentRecord.RecordId, service2.CurrentRecord.RecordId);
        }

        const string sharedSecret = "+xEF24ekXQh1geVWpvTvg0BT8OP6g4LWvooZXiE+ftyjU+5U3dxyR7MdzlEgDTznepXDNEEpcCvbxTv2Dx5qxQ==";
        const string sessionToken = "ASAAAEJsFrdImoBPhEuDFRUObCJw2M1gj+RhF8+q2oJ9N396v3NE9+kBK61ME168S+p52rvwiFKZW1xtxNi/DC+d7TRtL40j32fpDBB9OB22awEm4g5IkObUMC3jvaP00FzFISYqKO1dXtiQ7PklURP1wrPn7o7mxsaYIo4TmN2ftTWvWs9MJ6konzREIguU0JrtX1iNEuGlkOS+xs8q/2MRB6gNL4TWWTiPWwYoqECYNSwoafw4Kv8RqUJ+mJ2dUGVxpDLhsWSYDhHMa8KpQr94dMSJyn6mhnEBIynwk5BcJ1qvxpn2zw==";

        string GetValidCastCallResult()
        {
            return @"<response><status><code>0</code></status><wc:info xmlns:wc=""urn:com.microsoft.wc.methods.response.CreateAuthenticatedSessionToken2"">" + 
                   @"<token app-id=""99999999-9999-9999-9999-999999999999"" app-record-auth-action=""NoActionRequired"">" + sessionToken + "</token>" + 
                   "<shared-secret>" + sharedSecret + "</shared-secret></wc:info></response>";
        }


        string GetCastCallInvalidAppResult()
        {
            return  @"<?xml version=""1.0"" encoding=""utf-8""?><response><status><code>6</code><error><message>The application could not be found.</message><context><server-name>ERICGU04</server-name><server-ip>fe80::782d:2010:f57b:f715%10</server-ip><server-ip>2001:4898:71:2:782d:2010:f57b:f715</server-ip><server-ip>fe80::5efe:10.137.86.170%11</server-ip><server-ip>2001:4898:0:fff:0:5efe:10.137.86.170</server-ip><server-ip>10.137.86.170</server-ip>" + 
                    @"<exception></exception></context></error></status></response>";
        }


        string GetAuthorizePeopleResultEmpty()
        {
            return  @"<response><status><code>0</code></status><wc:info xmlns:wc=""urn:com.microsoft.wc.methods.response.GetAuthorizedPeople"">" +
                    @"<response-results></response-results></wc:info></response>";
        }

        string GetAuthorizedPeopleResultOne()
        {
            return
            @"<response><status><code>0</code></status>" +
            @"<wc:info xmlns:wc=""urn:com.microsoft.wc.methods.response.GetAuthorizedPeople""><response-results><person-info>" +
            @"<person-id>68701ce3-00f5-4407-a741-d20f13c375d6</person-id><name>Sean Test</name>" +
            @"<record id=""99999999-9999-9999-9999-999999999999"" record-custodian=""true"" rel-type=""1"" rel-name=""Self"" " +
                @"auth-expires=""2070-01-01T00:00:00Z"" display-name=""Sean's Test Record"" state=""Active"" date-created=""2011-02-18T17:14:44.217Z"" " +
                @"max-size-bytes=""104857600"" size-bytes=""1115"" app-record-auth-action=""NoActionRequired"">Sean's Test Record</record>" +
            @"</person-info><more-results>false</more-results></response-results></wc:info></response>";
        }

        string GetAuthorizedPeopleResultOneGoodOneBad()
        {
            return
            @"<response><status><code>0</code></status>" +
            @"<wc:info xmlns:wc=""urn:com.microsoft.wc.methods.response.GetAuthorizedPeople""><response-results><person-info>" +
            @"<person-id>68701ce3-00f5-4407-a741-d20f13c375d6</person-id><name>Sean Test</name>" +
            @"<record id=""99999999-9999-9999-9999-999999999999"" record-custodian=""true"" rel-type=""1"" rel-name=""Self"" " +
                @"auth-expires=""2070-01-01T00:00:00Z"" display-name=""Sean's Test Record"" state=""Active"" date-created=""2011-02-18T17:14:44.217Z"" " +
                @"max-size-bytes=""104857600"" size-bytes=""1115"" app-record-auth-action=""NoActionRequired"">Sean's Test Record</record>" +
            @"<record id=""99999999-9999-9999-9999-999999999988"" record-custodian=""true"" rel-type=""1"" rel-name=""Self"" " +
                @"auth-expires=""2070-01-01T00:00:00Z"" display-name=""Bad record"" state=""Active"" date-created=""2011-02-18T17:14:44.217Z"" " +
                @"max-size-bytes=""104857600"" size-bytes=""1115"" app-record-auth-action=""AuthorizationRequired "">bad record</record>" +
            @"</person-info><more-results>false</more-results></response-results></wc:info></response>";
        }

        string GetAuthorizedPeopleResultOneBad()
        {
            return
            @"<response><status><code>0</code></status>" +
            @"<wc:info xmlns:wc=""urn:com.microsoft.wc.methods.response.GetAuthorizedPeople""><response-results><person-info>" +
            @"<person-id>68701ce3-00f5-4407-a741-d20f13c375d6</person-id><name>Sean Test</name>" +
            @"<record id=""99999999-9999-9999-9999-999999999988"" record-custodian=""true"" rel-type=""1"" rel-name=""Self"" " +
                @"auth-expires=""2070-01-01T00:00:00Z"" display-name=""Bad record"" state=""Active"" date-created=""2011-02-18T17:14:44.217Z"" " +
                @"max-size-bytes=""104857600"" size-bytes=""1115"" app-record-auth-action=""AuthorizationRequired "">bad record</record>" +
            @"</person-info><more-results>false</more-results></response-results></wc:info></response>";
        }

        string NewApplicationCreationInfoSuccess()
        {
            return
                @"<response><status><code>0</code></status><wc:info xmlns:wc=""urn:com.microsoft.wc.methods.response.NewApplicationCreationInfo"">" +
                @"<app-id>106b443f-3b14-4064-9055-eaf8bb05c206</app-id><shared-secret>PRZoiwotdtjU444q+63M22H/v5zc/MozY/y4gcu17hA=</shared-secret>" +
                @"<app-token>ASAAANQgT2YQJwRHpCLOMJXTvlmkPBRmpPB9SzPNHzMndfpiVKBij2RgkLRrQY+oKFKzHP9KxJnFxAC8AyIT77HgfCs1Wq7gol4WovDHAkgslSWMLYEesBLF4i/5DXLr/clsU88vlNR3LKYQSHb8BGcr2wqNGHXFN2I092YeCcN8pujwB6GzXcuTQwvnrs4UB8YbCe8lDMf0ugSH0P12PObFwes9Ya5BRP2TtsFtmVPv+yesNtl8CoglFrzDfA5qb4m7jt4IlFsBHRldPOPA1jFNWHGUJrMdO+ZbR0coG0aSac5S8oIUBKqpI5bWzWwxCoz9luntD6oYvWvY0IFU+zjdrKOHIUIB</app-token>" +
                @"</wc:info></response>";
        }

        string GetAuthorizedPeopleResultTwoPeople()
        {
            return
            @"<response><status><code>0</code></status>" +
            @"<wc:info xmlns:wc=""urn:com.microsoft.wc.methods.response.GetAuthorizedPeople""><response-results>" +
            @"<person-info><person-id>68701ce3-00f5-4407-a741-d20f13c375d6</person-id><name>Sean Test</name>" +
                @"<record id=""99999999-9999-9999-9999-999999999999"" record-custodian=""true"" rel-type=""1"" rel-name=""Self"" " +
                @"auth-expires=""2070-01-01T00:00:00Z"" display-name=""Sean's Test Record"" state=""Active"" date-created=""2011-02-18T17:14:44.217Z"" " +
                @"max-size-bytes=""104857600"" size-bytes=""1115"" app-record-auth-action=""NoActionRequired"">Sean's Test Record</record>" +
            @"</person-info>" +
            @"<person-info><person-id>68701ce3-00f5-4407-a741-d20f13c375d0</person-id><name>Somebody Test</name>" +
                @"<record id=""99999999-9999-9999-9999-999999999998"" record-custodian=""true"" rel-type=""1"" rel-name=""Pet"" " +
                @"auth-expires=""2070-01-01T00:00:00Z"" display-name=""Somebody's Test Record"" state=""Active"" date-created=""2011-02-18T17:14:44.217Z"" " +
                @"max-size-bytes=""104857600"" size-bytes=""1115"" app-record-auth-action=""NoActionRequired"">Somebody's Test Record</record>" +
            @"</person-info>" +
            @"<more-results>false</more-results></response-results></wc:info></response>";
        }

        AutoResetEvent _authenticationCompleteEvent;
        AutoResetEvent _doShellAuthenticationEvent;
        HealthVaultResponseEventArgs _authenticationCompleteEventArgs;
        HealthVaultResponseEventArgs _doShellAuthenticationEventArgs;


        void AuthenticationCompleted(object sender, HealthVaultResponseEventArgs e)
        {
            _authenticationCompleteEventArgs = e;
            _authenticationCompleteEvent.Set();
        }

        void DoShellAuthentication(object sender, HealthVaultResponseEventArgs e)
        {
            _doShellAuthenticationEventArgs = e;
            _doShellAuthenticationEvent.Set();
        }

        void WaitSetup()
        {
            _authenticationCompleteEvent = new AutoResetEvent(false);
            _doShellAuthenticationEvent = new AutoResetEvent(false);

            _authenticationCompleteEventArgs = null;
            _doShellAuthenticationEventArgs = null;
        }

        void WaitForEither()
        {
            WaitHandle[] handles = new AutoResetEvent[2];
            handles[0] = _authenticationCompleteEvent;
            handles[1] = _doShellAuthenticationEvent;

            WaitHandle.WaitAny(handles);
        }

        [Test]
        public void CASTCallSuccess()
        {
            HealthVaultService service = GetNullService();
            byte[] key = new byte[] { 1, 3, 5, 7, 9, 11 };
            service.SharedSecret = Convert.ToBase64String(key);
            Assert.IsNull(service.SessionSharedSecret);
            Assert.IsNull(service.AuthorizationSessionToken);

            WaitSetup();

            WebRequestMock castMock = new WebRequestMock(GetValidCastCallResult());
            WebRequestMock noAuthorizedUsersMock = new WebRequestMock(GetAuthorizedPeopleResultOne());
            HealthVaultRequest.EnableMocks(castMock, noAuthorizedUsersMock);

            service.BeginAuthenticationCheck(AuthenticationCompleted, DoShellAuthentication);

            WaitForEither();

            Assert.AreEqual(sharedSecret, service.SessionSharedSecret);
            Assert.AreEqual(sessionToken, service.AuthorizationSessionToken);
        }

        [Test]
        public void CASTCallInvalidApp()
        {
            HealthVaultService service = GetNullService();
            byte[] key = new byte[] { 1, 3, 5, 7, 9, 11 };
            service.SharedSecret = Convert.ToBase64String(key);
            Assert.IsNull(service.SessionSharedSecret);
            Assert.IsNull(service.AuthorizationSessionToken);

            WaitSetup();

            WebRequestMock castMock = new WebRequestMock(GetCastCallInvalidAppResult());
            WebRequestMock newAppSuccessMock = new WebRequestMock(NewApplicationCreationInfoSuccess());
            HealthVaultRequest.EnableMocks(castMock, newAppSuccessMock);

            service.BeginAuthenticationCheck(AuthenticationCompleted, DoShellAuthentication);

            WaitForEither();

            // If this works correctly, we get an "invalid app" and then 
            // should have gotten the new app information and then called out to do the auth...

            Assert.IsNotNull(_doShellAuthenticationEventArgs);
        }

        [Test]
        public void NoAuthorizedPeople()
        {
            HealthVaultService service = GetNullService();
            byte[] key = new byte[] { 1, 3, 5, 7, 9, 11 };
            service.SharedSecret = Convert.ToBase64String(key);
            Assert.IsNull(service.SessionSharedSecret);
            Assert.IsNull(service.AuthorizationSessionToken);

            WaitSetup();

            WebRequestMock castMock = new WebRequestMock(GetValidCastCallResult());
            WebRequestMock noAuthorizedUsersMock = new WebRequestMock(GetAuthorizePeopleResultEmpty());
            HealthVaultRequest.EnableMocks(castMock, noAuthorizedUsersMock);

            service.BeginAuthenticationCheck(AuthenticationCompleted, DoShellAuthentication);

            WaitForEither();

            Assert.IsNotNull(_doShellAuthenticationEventArgs);
            Assert.AreEqual(0, service.Records.Count);
        }


        [Test]
        public void AuthorizedPeopleSuccess()
        {
            HealthVaultService service = GetNullService();
            byte[] key = new byte[] { 1, 3, 5, 7, 9, 11 };
            service.SharedSecret = Convert.ToBase64String(key);
            Assert.IsNull(service.SessionSharedSecret);
            Assert.IsNull(service.AuthorizationSessionToken);

            WaitSetup();

            WebRequestMock castMock = new WebRequestMock(GetValidCastCallResult());
            WebRequestMock noAuthorizedUsersMock = new WebRequestMock(GetAuthorizedPeopleResultOne());
            HealthVaultRequest.EnableMocks(castMock, noAuthorizedUsersMock);

            service.BeginAuthenticationCheck(AuthenticationCompleted, DoShellAuthentication);

            WaitForEither();

            Assert.AreEqual(1, service.Records.Count);
            Assert.AreEqual(new Guid("68701ce3-00f5-4407-a741-d20f13c375d6"), service.Records[0].PersonId);
            Assert.AreEqual(new Guid("99999999-9999-9999-9999-999999999999"), service.Records[0].RecordId);
            Assert.AreEqual("Sean Test", service.Records[0].PersonName);
            Assert.AreEqual("Sean's Test Record", service.Records[0].RecordName);
        }


        [Test]
        public void AuthorizedTwoPeopleSuccess()
        {
            HealthVaultService service = GetNullService();
            byte[] key = new byte[] { 1, 3, 5, 7, 9, 11 };
            service.SharedSecret = Convert.ToBase64String(key);
            Assert.IsNull(service.SessionSharedSecret);
            Assert.IsNull(service.AuthorizationSessionToken);

            WaitSetup();

            WebRequestMock castMock = new WebRequestMock(GetValidCastCallResult());
            WebRequestMock noAuthorizedUsersMock = new WebRequestMock(GetAuthorizedPeopleResultTwoPeople());
            HealthVaultRequest.EnableMocks(castMock, noAuthorizedUsersMock);

            service.BeginAuthenticationCheck(AuthenticationCompleted, DoShellAuthentication);

            WaitForEither();

            Assert.AreEqual(2, service.Records.Count);
            Assert.AreEqual(new Guid("68701ce3-00f5-4407-a741-d20f13c375d6"), service.Records[0].PersonId);
            Assert.AreEqual(new Guid("99999999-9999-9999-9999-999999999999"), service.Records[0].RecordId);
            Assert.AreEqual("Sean Test", service.Records[0].PersonName);
            Assert.AreEqual("Sean's Test Record", service.Records[0].RecordName);
            Assert.AreEqual(new Guid("68701ce3-00f5-4407-a741-d20f13c375d0"), service.Records[1].PersonId);
            Assert.AreEqual(new Guid("99999999-9999-9999-9999-999999999998"), service.Records[1].RecordId);
            Assert.AreEqual("Somebody Test", service.Records[1].PersonName);
            Assert.AreEqual("Somebody's Test Record", service.Records[1].RecordName);
        }

        HealthVaultRecord CreateRecord(Guid personId, string personName, Guid recordId)
        {
            return HealthVaultRecord.Create(personId, personName, @"<record id=""" + recordId.ToString() + @""" app-record-auth-action=""NoActionRequired""" +
                                                                                    @">Frecord</record>");
        }

        [Test]
        public void RestoreSetCurrentRecordProperly()
        {
            // Test that when we call GetAuthorizePeople, we will match the saved record and person ids that we loaded from storage
            // and update the current record properly.

            HealthVaultService service = new HealthVaultService("https://platform.healthvault-ppe.com", "https://account.healthvault-ppe.com/", Guid.NewGuid());

            service.AppIdInstance = new Guid("ce121dd2-7b5b-40f4-b41f-01d16f23e391");
            service.ApplicationCreationToken = "ASAAADNt1Jwbx…+wsXjPFs00soe9w==xxx";
            service.AuthorizationSessionToken = "ASAAADNt1Jwbx…+wsXjPFs00soe9w==";
            service.SharedSecret = Convert.ToBase64String(Encoding.UTF8.GetBytes("My test key"));
            service.Country = "CA";
            service.Language = "fr";
            service.SessionSharedSecret = Convert.ToBase64String(Encoding.UTF8.GetBytes("My session key"));

            Guid personId = new Guid("68701ce3-00f5-4407-a741-d20f13c375d6");
            string personName = "Fred";
            Guid recordId = new Guid("99999999-9999-9999-9999-999999999999");

            service.CurrentRecord = CreateRecord(personId, personName, recordId);
            service.SaveSettings("TestSettings");

            HealthVaultService service2 = new HealthVaultService("https://platform.healthvault-ppe.com", "https://account.healthvault-ppe.com/", Guid.NewGuid());
            service2.LoadSettings("TestSettings");
            byte[] key = new byte[] { 1, 3, 5, 7, 9, 11 };
            service2.SharedSecret = Convert.ToBase64String(key);

            WaitSetup();

            WebRequestMock noAuthorizedUsersMock = new WebRequestMock(GetAuthorizedPeopleResultOne());
            HealthVaultRequest.EnableMocks(noAuthorizedUsersMock);

            service2.BeginAuthenticationCheck(AuthenticationCompleted, DoShellAuthentication);

            WaitForEither();

            Assert.AreEqual(1, service2.Records.Count);
            Assert.AreEqual(new Guid("68701ce3-00f5-4407-a741-d20f13c375d6"), service2.CurrentRecord.PersonId);
            Assert.AreEqual(new Guid("99999999-9999-9999-9999-999999999999"), service2.CurrentRecord.RecordId);
            Assert.AreEqual("Sean Test", service2.CurrentRecord.PersonName);
            Assert.AreEqual("Sean's Test Record", service2.CurrentRecord.RecordName);
        }

        [Test]
        public void AuthorizedPeopleOneGoodOneBadRecord()
        {
            HealthVaultService service = GetNullService();
            byte[] key = new byte[] { 1, 3, 5, 7, 9, 11 };
            service.SharedSecret = Convert.ToBase64String(key);
            Assert.IsNull(service.SessionSharedSecret);
            Assert.IsNull(service.AuthorizationSessionToken);

            WaitSetup();

            WebRequestMock castMock = new WebRequestMock(GetValidCastCallResult());
            WebRequestMock noAuthorizedUsersMock = new WebRequestMock(GetAuthorizedPeopleResultOneGoodOneBad());
            HealthVaultRequest.EnableMocks(castMock, noAuthorizedUsersMock);

            service.BeginAuthenticationCheck(AuthenticationCompleted, DoShellAuthentication);

            WaitForEither();

            Assert.AreEqual(1, service.Records.Count);
            Assert.AreEqual(new Guid("68701ce3-00f5-4407-a741-d20f13c375d6"), service.Records[0].PersonId);
            Assert.AreEqual(new Guid("99999999-9999-9999-9999-999999999999"), service.Records[0].RecordId);
            Assert.AreEqual("Sean Test", service.Records[0].PersonName);
            Assert.AreEqual("Sean's Test Record", service.Records[0].RecordName);
        }


        [Test]
        public void AuthorizedPeopleOneBadRecord()
        {
            HealthVaultService service = GetNullService();
            byte[] key = new byte[] { 1, 3, 5, 7, 9, 11 };
            service.SharedSecret = Convert.ToBase64String(key);
            Assert.IsNull(service.SessionSharedSecret);
            Assert.IsNull(service.AuthorizationSessionToken);

            WaitSetup();

            WebRequestMock castMock = new WebRequestMock(GetValidCastCallResult());
            WebRequestMock noAuthorizedUsersMock = new WebRequestMock(GetAuthorizedPeopleResultOneBad());
            HealthVaultRequest.EnableMocks(castMock, noAuthorizedUsersMock);

            service.BeginAuthenticationCheck(AuthenticationCompleted, DoShellAuthentication);

            WaitForEither();

            Assert.IsNotNull(_doShellAuthenticationEventArgs);
            Assert.AreEqual(0, service.Records.Count);
        }

        [Test]
        public void NoSharedSecretCallNewApplicationCreationInfo()
        {
            HealthVaultService service = GetNullService();

            WaitSetup();

            WebRequestMock newApplicationCreationInfoMock = new WebRequestMock(NewApplicationCreationInfoSuccess());
            //WebRequestMock castMock = new WebRequestMock(GetValidCastCallResult());
            //WebRequestMock noAuthorizedUsersMock = new WebRequestMock("");
            HealthVaultRequest.EnableMocks(newApplicationCreationInfoMock);

            service.BeginAuthenticationCheck(AuthenticationCompleted, DoShellAuthentication);

            WaitForEither();

            Assert.IsNotNull(_doShellAuthenticationEventArgs);
            Assert.AreNotEqual(Guid.Empty, service.AppIdInstance);
        }

        static string GetExpiredSessionTokenResponse()
        {
            return
            @"    <response>
        <status>
            <code>65</code>
            <error>
                <message>The authenticated session token has expired.</message>
                <context>
                    <server-name>HSWEBP104T</server-name>
                    <server-ip>::1</server-ip>
                    <server-ip>192.168.20.97</server-ip>
                    <server-ip>10.196.100.156</server-ip>
                    <exception><![CDATA[Microsoft.Health.Platform.WildcatStatusException: The authenticated session token has expired.
   at Microsoft.Health.Platform.WCAuthSessionCredential.ParseAndVerifyAuthSessionToken(WildcatRequestContext ctx, String authToken) in e:\src\hsg-hv-next\private\hv\prod\src\platform\code\Authentication\WCAuthSessionCredential.cs:line 247
   at Microsoft.Health.Platform.WildcatExternalRequest.ParseAndVerifyAuthTokens() in e:\src\hsg-hv-next\private\hv\prod\src\platform\code\http\WildcatRequest.cs:line 1535
   at Microsoft.Health.Platform.WildcatRequestBase.SetupAndVerifyAuthenticationInfo() in e:\src\hsg-hv-next\private\hv\prod\src\platform\code\http\WildcatRequest.cs:line 1832
   at Microsoft.Health.Platform.WildcatRequestBase.Validate() in e:\src\hsg-hv-next\private\hv\prod\src\platform\code\http\WildcatRequest.cs:line 1674
   at Microsoft.Health.Platform.WildcatHttpHandlerBase.ProcessRequest() in e:\src\hsg-hv-next\private\hv\prod\src\platform\code\http\WildcatHttpRequest.cs:line 1178]]></exception>
                </context>
            </error>
        </status>
    </response>";
        }


        [Test]
        public void ExpiredSessionTokenCastHappens()
        {
            HealthVaultService service = GetNullService();
            service.SharedSecret = Convert.ToBase64String(Encoding.UTF8.GetBytes("My test key"));

            WebRequestMultipleMock expiredSessionTokenMock = new WebRequestMultipleMock(GetExpiredSessionTokenResponse(), GetThingsOneWeightXml());
            WebRequestMock castSuccessMock = new WebRequestMock(GetValidCastCallResult());
            HealthVaultRequest.EnableMocks(castSuccessMock);

            HealthVaultRequest request = new HealthVaultRequest("GetThings", "2", null, SendRequestResponseReceived);
            request.WebRequest = expiredSessionTokenMock;

            asyncTestEvent = new AutoResetEvent(false);
            service.BeginSendRequest(request);

            asyncTestEvent.WaitOne();

            Assert.IsNotNull(eventArgs.Response);
            Assert.AreEqual(0, HealthVaultRequest.MockRequestCount);
        }

        void SendRequestResponseReceived(object sender, HealthVaultResponseEventArgs e)
        {
            eventArgs = e;
            asyncTestEvent.Set();
        }

        static string GetServiceDefinitionXml = @"<response>
    <status>
        <code>0</code>
    </status>
    <wc:info xmlns:wc=""urn:com.microsoft.wc.methods.response.GetServiceDefinition2"">
        <platform>
            <url>https://platform.healthvault-ppe.com/platform/wildcat.ashx</url>
            <version>1.5.1011.5826</version>
            <configuration key=""allowedDocumentExtensions"">.avi,.bmp,.ccd,.ccr,.cda,.doc,.docm,.docx,.eml,.gif,.jpg,.mp3,.one,.pdf,.png,.ppsm,.ppsx,.ppt,.pptm,.pptx,.pub,.rpmsg,.rtf,.tif,.tiff,.txt,.vsd,.wav,.wma,.wmv,.xls,.xlsb,.xlsm,.xlsx,.xml,.xps</configuration>
        </platform>
        <shell>
            <url>https://account.healthvault-ppe.com/</url>
            <redirect-url>https://account.healthvault-ppe.com/redirect.aspx</redirect-url>
            <redirect-token>
                <token>APPAUTH</token>
                <description>Redirects to the Shell application authorization page. On successful authentication and verification of authorization the Shell will redirect to the application action URL with the target set to AppAuthSuccess. If authorization is declined by the user, then the Shell will redirect to the application action URL with the target set to AppAuthRejected.</description>
                <querystring-parameters>appid,actionqs</querystring-parameters>
            </redirect-token>
        </shell>
        <xml-method>
            <name>AddApplication</name>
            <version number=""1"">
                <request-schema-url>https://platform.healthvault-ppe.com/platform/XSD/method-addapplication.xsd</request-schema-url>
                <response-schema-url>https://platform.healthvault-ppe.com/platform/XSD/response-addapplication.xsd</response-schema-url>
            </version>
            <version number=""2"">
                <request-schema-url>https://platform.healthvault-ppe.com/platform/XSD/method-addapplication.xsd</request-schema-url>
                <response-schema-url>https://platform.healthvault-ppe.com/platform/XSD/response-addapplication.xsd</response-schema-url>
            </version>
        </xml-method>
        <common-schema>https://platform.healthvault-ppe.com/platform/XSD/types.xsd</common-schema>
    </wc:info>
</response>";

        static string GetThingsOneWeightXml()
        {
            return @"
<response>
    <status>
        <code>0</code>
    </status>
    <wc:info xmlns:wc=""urn:com.microsoft.wc.methods.response.GetThings3"">
        <group>
            <thing>
                <thing-id version-stamp=""197bcb46-c19f-489c-8891-f281f7a399f5"">9744d76b-dc5a-4f8e-98ad-5c84842ecea8</thing-id>
                <type-id name=""Weight Measurement"">3d34d87e-7fc1-4153-800f-f56592cb0d17</type-id>
                <thing-state>Active</thing-state>
                <flags>0</flags>
                <eff-date>2011-02-25T10:51:06.166</eff-date>
                <data-xml>
                    <weight>
                        <when>
                            <date>
                                <y>2011</y>
                                <m>2</m>
                                <d>25</d>
                            </date>
                            <time>
                                <h>10</h>
                                <m>51</m>
                                <s>6</s>
                                <f>166</f>
                            </time>
                        </when>
                        <value>
                            <kg>79.3103</kg>
                            <display units=""pounds"">174.8</display>
                        </value>
                    </weight>
                    <common/>
                </data-xml>
            </thing>
        </group>
    </wc:info>
</response>
";
        }
    }
}
